package org.zhtkj.jt808.codec;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.zhtkj.framework.codec.MessageDecoder;
import org.zhtkj.framework.codec.MessageEncoder;
import org.zhtkj.web.config.Charsets;
import org.zhtkj.web.jt808.codec.JT808MessageDecoder;
import org.zhtkj.web.jt808.codec.JT808MessageEncoder;
import org.zhtkj.web.jt808.dto.Authentication;
import org.zhtkj.web.jt808.dto.PositionAttribute;
import org.zhtkj.web.jt808.dto.PositionReport;
import org.zhtkj.web.jt808.dto.Register;
import org.zhtkj.web.jt808.dto.basics.Header;
import org.zhtkj.web.utils.JT808ProtocolUtils;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;

public class Client implements Runnable {
	private static String host = "192.168.0.57";
	private static int port = 7611;
	private static byte delimiter = 0x7e;
	private int flowid = 0;
	private String phone;
	private String terminalId;
    private MessageDecoder decoder = new JT808MessageDecoder(Charsets.GBK);
    private MessageEncoder<Header> encoder = new JT808MessageEncoder(Charsets.GBK);
    private Channel channel;
    private ClientHandle clientHandler;
    private SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");
	
	public Client(int index) {
		this.phone = String.format("%012d", index);
		this.terminalId = String.format("%07d", index);
		this.clientHandler = new ClientHandle(decoder);
	}
	
	public void start() throws Exception{
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			 Bootstrap bootstrap = new Bootstrap();
			 bootstrap.group(group);
			 bootstrap.channel(NioSocketChannel.class);
			 bootstrap.remoteAddress(host, port);
			 bootstrap.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1480, Unpooled.wrappedBuffer(new byte[]{delimiter}), Unpooled.wrappedBuffer(new byte[]{delimiter, delimiter})));
					ch.pipeline().addLast(clientHandler);
				}
			 });
			 
			 this.channel = bootstrap.connect(host,port).sync().channel();
		} finally {
			 //group.shutdownGracefully().sync();
		}
	}
	
	public void register() {
		Register r = new Register();
		r.setHeader(newHeader(0x0100));
		r.setProvinceId(43);
		r.setCityId(4301);
		r.setManufacturerId("HK");
		r.setTerminalNumber(terminalId);
		r.setTerminalType("5505");
		r.setLicensePlateColor(0);
		r.setLicensePlate(terminalId);
		ByteBuf buf = JT808ProtocolUtils.doEscape4Send(encoder.encodeAll(r));
		ByteBuf allResultBuf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[]{delimiter}), buf, Unpooled.wrappedBuffer(new byte[]{delimiter}));
		channel.writeAndFlush(allResultBuf);
	}
	
	public void auth() throws Exception{
		Authentication au = new Authentication();
		au.setHeader(newHeader(0x0102));
		while(clientHandler.replyToken == null)
			Thread.sleep(200);
		au.setAuthCode(clientHandler.replyToken);
		ByteBuf buf = JT808ProtocolUtils.doEscape4Send(encoder.encodeAll(au));
		ByteBuf allResultBuf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[]{delimiter}), buf, Unpooled.wrappedBuffer(new byte[]{delimiter}));
		channel.writeAndFlush(allResultBuf);
	}
	
	public void location() {
		PositionReport pr = new PositionReport();
		pr.setHeader(newHeader(0x0200));
		pr.setWarningMark(0x0);
		pr.setStatus(0x04000013 );
		pr.setLatitude(0x01AEADED);
		pr.setLongitude(0x06BA9642);
		pr.setAltitude(0x8E);
		pr.setSpeed(0x0A);
		pr.setDirection(0x0);
		pr.setReportTime(df.format(new Date()));
		List<PositionAttribute> pal = new ArrayList<PositionAttribute>();
		PositionAttribute pa = new PositionAttribute();
		pa.setId(0x01);
		pa.setLength(4);
		pa.setBytesValue(new byte[] {0,0,0,0});
		pal.add(pa);
		pa = new PositionAttribute();
		pa.setId(0xE1);
		pa.setLength(4);
		pa.setBytesValue(new byte[] {0,0,0,0});
		pal.add(pa);
		pa = new PositionAttribute();
		pa.setId(0xE5);
		pa.setLength(4);
		pa.setBytesValue(new byte[] {0x7D,0,0,0});
		pal.add(pa);
		pr.setPositionAttributes(pal);
		pa = new PositionAttribute();
		pa.setId(0xF3);
		pa.setLength(2);
		pa.setBytesValue(new byte[] {0, 0});
		pal.add(pa);
		ByteBuf buf = JT808ProtocolUtils.doEscape4Send(encoder.encodeAll(pr));
		ByteBuf allResultBuf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[]{delimiter}), buf, Unpooled.wrappedBuffer(new byte[]{delimiter}));
		channel.writeAndFlush(allResultBuf);	
	}
	
    public Header newHeader(int typeId) {
        Header header = new Header();
        header.setType(typeId);
        header.setTerminalPhone(phone);
        header.setFlowId(flowid++);
        header.setEncryptionType(0);
        header.setReservedBit(0);
        return header;
    }

 
	/**
	 * @Description: 发送错误的注册包   
	 */
	public void errorRegister() {
		Register r = new Register();
		r.setHeader(newHeader(0x0100));
		r.setProvinceId(43);
		ByteBuf buf = JT808ProtocolUtils.doEscape4Send(encoder.encodeAll(r));
		ByteBuf allResultBuf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[]{delimiter}), buf, Unpooled.wrappedBuffer(new byte[]{delimiter}));
		channel.writeAndFlush(allResultBuf);
	}
	
	/**
	 * @Description: 发送错误的鉴权包
	 */
	public void errorAuth() throws Exception{
		Authentication au = new Authentication();
		au.setHeader(newHeader(0x0102));
		while(clientHandler.replyToken == null)
			Thread.sleep(200);
		au.setAuthCode("666");
		ByteBuf buf = JT808ProtocolUtils.doEscape4Send(encoder.encodeAll(au));
		ByteBuf allResultBuf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[]{delimiter}), buf, Unpooled.wrappedBuffer(new byte[]{delimiter}));
		channel.writeAndFlush(allResultBuf);
	}
	
	/**
	 * @Description: 发送错误的位置信息包   
	 */
	public void errorLocation() {
		PositionReport pr = new PositionReport();
		pr.setHeader(newHeader(0x0200));
		pr.setWarningMark(0x0);
		pr.setStatus(0x04000013 );
		pr.setLatitude(0x01AEADED);
		pr.setLongitude(0x06BA9642);
		pr.setAltitude(0x8E);
		pr.setSpeed(0x0A);
		pr.setDirection(0x0);
		pr.setReportTime("1966215821");
		List<PositionAttribute> pal = new ArrayList<PositionAttribute>();
		PositionAttribute pa = new PositionAttribute();
		pa.setId(0x01);
		pa.setLength(4);
		pa.setBytesValue(new byte[] {0,0,0,0});
		pal.add(pa);
		pa = new PositionAttribute();
		pa.setId(0xE1);
		pa.setLength(4);
		pa.setBytesValue(new byte[] {0,0,0,0});
		pal.add(pa);
		pa = new PositionAttribute();
		pa.setId(0xE5);
		pa.setLength(4);
		pa.setBytesValue(new byte[] {0x7D,0,0,0});
		pal.add(pa);
		pr.setPositionAttributes(pal);
		pa = new PositionAttribute();
		pa.setId(0xF3);
		pa.setLength(2);
		pa.setBytesValue(new byte[] {0, 0});
		pal.add(pa);
		ByteBuf buf = JT808ProtocolUtils.doEscape4Send(encoder.encodeAll(pr));
		ByteBuf allResultBuf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[]{delimiter}), buf, Unpooled.wrappedBuffer(new byte[]{delimiter}));
		channel.writeAndFlush(allResultBuf);	
	}
	
	@Override
	public void run() {
		try {
			start();
			register();
			auth();
			Thread.sleep(2000);
			while(true) {
				location();
				Thread.sleep(15000);
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}	
}